fix: propagate auth errors (401/403) immediately instead of falling b…#1444
fix: propagate auth errors (401/403) immediately instead of falling b…#1444xue-cai wants to merge 1 commit intomodelcontextprotocol:mainfrom
Conversation
158fc82 to
7405d8b
Compare
…ack to SSE When AutoDetectingClientSessionTransport receives a 401 or 403 from the initial Streamable HTTP POST, it should NOT fall back to SSE transport. Auth errors are not transport-related — the server understood the request but rejected the credentials. Falling back to SSE would: 1. Fail with the same credentials (or a different transport error) 2. Mask the real authentication error from the caller This was discovered investigating Azure AI Search MCP endpoints returning 403 on Streamable HTTP POST, which caused the SDK to fall back to SSE GET, resulting in a confusing 405 error that hid the real auth failure. The fix adds an explicit check for 401/403 before the SSE fallback path, and throws HttpRequestException with the auth status code immediately. Code reference: AutoDetectingClientSessionTransport.InitializeAsync https://github.com/modelcontextprotocol/csharp-sdk/blob/v0.9.0-preview.2/src/ModelContextProtocol.Core/Client/AutoDetectingClientSessionTransport.cs#L61 Testing: # Build all frameworks (only netstandard2.0 fails — pre-existing on main): dotnet build tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' # Run auto-detect tests (4 tests × 3 frameworks = 12 total, 0 failures): dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~HttpClientTransportAutoDetectTests" --framework net10.0 dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~HttpClientTransportAutoDetectTests" --framework net9.0 dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~HttpClientTransportAutoDetectTests" --framework net8.0 # Run full transport suite (75 tests × 3 frameworks = 225 total, 0 failures): dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~Transport" --framework net10.0 dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~Transport" --framework net9.0 dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~Transport" --framework net8.0 Co-authored-by: Copilot <[email protected]>
7405d8b to
13a634c
Compare
|
Our auth retry logic ought to be at a lower layer than the AutoDetectingClientSessionTransport.cs, so if you can do the OAuth flow defined in https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization, that should work and we have a lot of tests for that. At a higher layer, falling back for any error seems right if you do choose the default auto transport. I don't think we should special-case status codes when they're not doing anything that's part of the spec. It is an annoying default behavior to get a 405 when the real issue is a 403, but if you're doing custom auth, you should know what transport you're using, so opting into TransportMode = HttpTransportMode.StreamableHttp should give you the desired behavior. Long term, we might just make that the default avoiding this entirely. Another thing to consider is capturing and rethrowing the original Streamable HTTP exception using ExceptoinDispatchInfo if the SSE fallback fails. |
…ack to SSE
When AutoDetectingClientSessionTransport receives a 401 or 403 from the initial Streamable HTTP POST, it should NOT fall back to SSE transport. Auth errors are not transport-related — the server understood the request but rejected the credentials. Falling back to SSE would:
This was discovered investigating Azure AI Search MCP endpoints returning 403 on Streamable HTTP POST, which caused the SDK to fall back to SSE GET, resulting in a confusing 405 error that hid the real auth failure.
The fix adds an explicit check for 401/403 before the SSE fallback path, and throws HttpRequestException with the auth status code immediately.
Code reference:
AutoDetectingClientSessionTransport.InitializeAsync
https://github.com/modelcontextprotocol/csharp-sdk/blob/v0.9.0-preview.2/src/ModelContextProtocol.Core/Client/AutoDetectingClientSessionTransport.cs#L61
Motivation and Context
How Has This Been Tested?
Breaking Changes
Types of changes
Checklist
Additional context